
#ifndef HASHEXTENSIBLE_H_
#define HASHEXTENSIBLE_H_

#include "TablaHash.h"
#include "../../ControladorIDsLibres/src/ControladorIDsLibres.h"

	typedef struct {
		FILE* archTabla;
		FILE* archBuckets;
		ControladorIDsLibres* controladorIDsLibres;
		TablaHash* Tabla;
		enum TBOOL esTemporal; //Indica si al cerrar el Hash se deben eliminar los archivos utilizados
		char * nombreArch; //nombre de archivo con el que se generan los 3 archivos que maneja la estructura
	}HashExtensible;

	typedef struct iteradorHash{

		Bucket * bucketActual;
		int numBucket;
		unsigned int indiceElemBucket;
	}iteradorHash;


	/* PRE: Recibe el nombre de la ruta del archivo de bloques. De no existir, lo crea.
	 * POS: Devuelve una estructura HashExtensible con los archivos abiertos, NULL en caso de error
	 */
	HashExtensible* CrearHashExtensible (TamBucket tamanioBloque,char* nombre);

	/* Libera los archivos que fueron creados, o abiertos
	 * PRE: Recibe la Estrctura Hash a liberar.
	 * POS: Cierra todos los archivos utilizados (Tabla, Bloques y Bloques Libres) y libera la memoria de la estructura.
			Escribe la Tabla de memoria al archivo con su último estado y deja inaccesibles a los archivos de datos y bloques libres
	 */
	void CerrarHashExtensible (HashExtensible* hash);

	/*Se divide 'bucket' en 2. De no ser posible, se duplica el tamaño de la tabla
	 * en la posicion recibe el indice de la tabla a modificar */
	Bucket* SplitBloque (HashExtensible* hash, Bucket* bucket, unsigned int indice);

	/*'bucket' esta lleno, 'nuevoBucket' esta vacio, se distribuyen las claves*/
	void DistribuirClaves(TablaHash tabla, Bucket* bucket, Bucket* nuevoBucket);

	/*Devuelve un elemento segun TClave, llama a BuscarElementoBloque*/
	void* ObtenerElemento (HashExtensible* hash, TClave clave);

	/*Esta funcion valida que haya espacio vacio y llama a InsertarElementoBloque*/
	int InsertarElemento(HashExtensible* hash,TClave clave, void* elemento, unsigned int tamElemento);

	/*llama a EliminarElementoBloque*/
	int EliminarElemento ( HashExtensible* hash, TClave clave);

	/*Valida la capacidad del bucket a insertar que no pase el 100%*/
	int ModificarElemento (HashExtensible* hash, TClave clave, void* elemento, unsigned short int tamElemento);

	/*Se llama antes de hacer un Split*/
	int sinEspacioEnBucket (HashExtensible* hash, Bucket* bucket, TClave clave, void* elemento, unsigned short int longElemento, unsigned int indice, enum TBOOL esInsercion);

	void visualizar(HashExtensible* hash, int full, FILE* salida);

	/*ITERADOR*/

	iteradorHash * CrearIteradorHash();

	void EliminarIteradorHash (iteradorHash * it);

	/* Devuelve el elemento siguiente del bucket levantado y su clave. Si no hay mas elementos en el bucket, levanta un nuevo bucket
	 * Devuelve NULL si no hay elementos para leer, y NULL en 'claveDevuelta'
	 * */
	void * getSiguienteElem (HashExtensible * hash, iteradorHash * it, TClave* claveDevuelta);

	/*FIN ITERADOR*/

	/*Es Temporal*/

	enum TBOOL getEsTemporal (HashExtensible * hash);

	void setEsTemporal (HashExtensible * hash, enum TBOOL esTemporal);

	/*FIN Es Temporal*/


#endif /*HASHEXTENSIBLE_H_*/
